import os
import logging
import gzip
import shutil
from logging.handlers import RotatingFileHandler
from datetime import datetime
import threading

class CompressedRotatingFileHandler(RotatingFileHandler):
    """支持压缩的轮转文件处理器"""

    def __init__(self, filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=False):
        super().__init__(filename, mode, maxBytes, backupCount, encoding, delay)

    def doRollover(self):
        """执行日志轮转并压缩旧文件"""
        if self.stream:
            self.stream.close()
            self.stream = None

        if self.backupCount > 0:
            for i in range(self.backupCount - 1, 0, -1):
                sfn = self.rotation_filename("%s.%d.gz" % (self.baseFilename, i))
                dfn = self.rotation_filename("%s.%d.gz" % (self.baseFilename, i + 1))
                if os.path.exists(sfn):
                    if os.path.exists(dfn):
                        os.remove(dfn)
                    os.rename(sfn, dfn)

            # 压缩当前日志文件
            dfn = self.rotation_filename(self.baseFilename + ".1.gz")
            if os.path.exists(dfn):
                os.remove(dfn)

            # 压缩当前文件到 .1.gz
            with open(self.baseFilename, 'rb') as f_in:
                with gzip.open(dfn, 'wb') as f_out:
                    shutil.copyfileobj(f_in, f_out)

            # 删除原文件
            os.remove(self.baseFilename)

        if not self.delay:
            self.stream = self._open()

class Logger:
    """日志工具类"""

    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
        return cls._instance

    def __init__(self):
        if hasattr(self, '_initialized'):
            return

        self._initialized = True
        self._loggers = {}
        self._setup_default_config()

    def _setup_default_config(self):
        """设置默认配置"""
        self.log_dir = 'logs'
        self.max_bytes = 10 * 1024 * 1024  # 10MB
        self.backup_count = 5  # 保留5个备份文件
        self.log_format = '%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
        self.date_format = '%Y-%m-%d %H:%M:%S'

        # 创建日志目录
        if not os.path.exists(self.log_dir):
            os.makedirs(self.log_dir)

    def get_logger(self, name='app', level=logging.INFO, log_to_file=True, log_to_console=False):
        """
        获取日志记录器

        Args:
            name: 日志记录器名称
            level: 日志级别
            log_to_file: 是否写入文件
            log_to_console: 是否输出到控制台

        Returns:
            logging.Logger: 配置好的日志记录器
        """
        if name in self._loggers:
            return self._loggers[name]

        logger = logging.getLogger(name)
        logger.setLevel(level)

        # 清除默认处理器
        logger.handlers.clear()

        # 创建格式器
        formatter = logging.Formatter(self.log_format, self.date_format)

        # 文件处理器
        if log_to_file:
            log_file = os.path.join(self.log_dir, f'{name}.log')
            file_handler = CompressedRotatingFileHandler(
                log_file,
                maxBytes=self.max_bytes,
                backupCount=self.backup_count,
                encoding='utf-8'
            )
            file_handler.setLevel(level)
            file_handler.setFormatter(formatter)
            logger.addHandler(file_handler)

        # 控制台处理器
        if log_to_console:
            console_handler = logging.StreamHandler()
            console_handler.setLevel(level)
            console_handler.setFormatter(formatter)
            logger.addHandler(console_handler)

        # 防止重复输出
        logger.propagate = False

        self._loggers[name] = logger
        return logger

    def configure(self, log_dir='logs', max_bytes=10*1024*1024, backup_count=5,
                  log_format=None, date_format=None):
        """
        配置日志系统

        Args:
            log_dir: 日志目录
            max_bytes: 单个日志文件最大大小（字节）
            backup_count: 备份文件数量
            log_format: 日志格式
            date_format: 日期格式
        """
        self.log_dir = log_dir
        self.max_bytes = max_bytes
        self.backup_count = backup_count

        if log_format:
            self.log_format = log_format
        if date_format:
            self.date_format = date_format

        # 重新创建日志目录
        if not os.path.exists(self.log_dir):
            os.makedirs(self.log_dir)

    def cleanup_old_logs(self, days=30):
        """
        清理超过指定天数的日志文件

        Args:
            days: 保留天数
        """
        if not os.path.exists(self.log_dir):
            return

        cutoff_time = datetime.now().timestamp() - (days * 24 * 60 * 60)

        for filename in os.listdir(self.log_dir):
            filepath = os.path.join(self.log_dir, filename)
            if os.path.isfile(filepath):
                file_time = os.path.getctime(filepath)
                if file_time < cutoff_time:
                    try:
                        os.remove(filepath)
                        print(f"已删除旧日志文件: {filename}")
                    except Exception as e:
                        print(f"删除日志文件失败 {filename}: {e}")

# 创建全局日志实例
_logger_instance = Logger()

# 便捷函数
def get_logger(name='app', level=logging.INFO, log_to_file=True, log_to_console=False):
    """获取日志记录器的便捷函数"""
    return _logger_instance.get_logger(name, level, log_to_file, log_to_console)

def configure_logging(**kwargs):
    """配置日志系统的便捷函数"""
    return _logger_instance.configure(**kwargs)

def cleanup_logs(days=30):
    """清理旧日志的便捷函数"""
    return _logger_instance.cleanup_old_logs(days)

# 预定义的日志记录器
app_logger = get_logger('app', logging.INFO)
error_logger = get_logger('error', logging.ERROR)
access_logger = get_logger('access', logging.INFO)
training_logger = get_logger('training', logging.INFO)

# 便捷的日志函数
def log_info(message, logger_name='app'):
    """记录信息日志"""
    logger = get_logger(logger_name)
    logger.info(message)

def log_error(message, logger_name='app'):
    """记录错误日志"""
    logger = get_logger(logger_name)
    logger.error(message)

def log_warning(message, logger_name='app'):
    """记录警告日志"""
    logger = get_logger(logger_name)
    logger.warning(message)

def log_debug(message, logger_name='app'):
    """记录调试日志"""
    logger = get_logger(logger_name)
    logger.debug(message)

def log_exception(message, logger_name='app'):
    """记录异常日志（包含堆栈信息）"""
    logger = get_logger(logger_name)
    logger.exception(message)